package com.theeviljames.linearAlgebra;

import java.util.Arrays;
import java.util.PriorityQueue;

import com.theeviljames.base.IMatrixOps;
import com.theeviljames.base.MatrixOps;

public class GaussianElimination {

	private static PriorityQueue<LinearEquation> equations = new PriorityQueue<LinearEquation>();
	private static IMatrixOps m = MatrixOps.getMatrixOps();
	
	/**
	 * Currently only solves systems with one RHS
	 *
	 */

	public static void addEquation(LinearEquation eq){
		equations.offer(eq);
	}
	
	public static double[][] getMatrixForm(){
		String labels = equations.peek().getLabels();
		Object[] eqs = equations.toArray();
		double[][] result = new double[equations.size()][labels.length()+1];
		for(int i = 0; i < equations.size(); i++){
			LinearEquation eq = (LinearEquation)eqs[i];
			for(int j =0; j < labels.length(); j++){
				result[i][j] = eq.getCoefficient(String.valueOf(labels.charAt(j)));
			}
			result[i][labels.length()] = eq.getRHS()[0];
		}
		return result;
	}
	
	public static void printMatrix(double[][] matrix){
		for(double[] row:matrix)System.out.println(Arrays.toString(row));
	}
	
	public static void solveSystem(){
		double[][] a = getMatrixForm();
		//ArrayList<double[][]> eliminations = new ArrayList<double[][]>();
		int n = a.length;
		for(int i = 0; i < n-1; i++){
			double[][] e = m.getIdentityMatrix(n);
			e[i+1][i] = -(a[i+1][i]/a[i][i]);
			System.out.println("Elimination Matrix " + i + ">");
			printMatrix(e);
			a = m.times(e, a);
		}
		printMatrix(a);
		double[] diag = m.diag(a);
		System.out.println(Arrays.toString(diag));
		double[] values = new double[diag.length];
		for(int i = diag.length-1; i >= 0; i--){
			double[] row = a[i];
			System.out.println(i + " " + Arrays.toString(row));
			for(int j = (diag.length-1); j > i; j--){
				row[j]=values[j]*row[j];
			}
			System.out.println(i + " " + Arrays.toString(row));
			double sum = row[row.length-1];
			for(int j = row.length-2; j > i; j--)sum -= row[j];
			values[i] = sum/row[i];
			       
		}
		
		String labels = equations.peek().getLabels();
		System.out.println(labels);
		System.out.println(Arrays.toString(values));
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try{
			//x+2y+z=2
			LinearEquation eq1 = new LinearEquation();
			eq1.setCoefficients(new double[]{1,2,1}, "xyz");
			eq1.setRHS(new double[]{2.0});
			//3x+8y+z=12
			LinearEquation eq2 = new LinearEquation();
			eq2.setCoefficients(new double[]{3,8,1}, "xyz");
			eq2.setRHS(new double[]{12.0});
			//0x+4y+z=2
			LinearEquation eq3 = new LinearEquation();
			eq3.setCoefficients(new double[]{0,4,1}, "xyz");
			eq3.setRHS(new double[]{2.0});
			
			//GaussianElimination gauss = new GaussianElimination();
			GaussianElimination.addEquation(eq1);
			GaussianElimination.addEquation(eq2);
			GaussianElimination.addEquation(eq3);
			
			double[][] matrix = GaussianElimination.getMatrixForm();
			System.out.println("Printing out the original matrix");
			printMatrix(matrix);
			System.out.println();
			GaussianElimination.solveSystem();
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}

}
